package com.jrx.anytxn.transaction.handler;

import com.jrx.anytxn.common.data.TxnRespCode;
import com.jrx.anytxn.common.exception.*;
import com.jrx.anytxn.common.uitl.StringUtils;
import com.jrx.anytxn.i18n.response.TxnRespResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 全局异常处理器
 */
@ControllerAdvice
public class GlobalExceptionHandler {
    private final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    private final Pattern pattern = Pattern.compile("\\[[\"']?(.+?)[\"']?]");

    private static final String EXCEPTION_HANDLER = "ExceptionHandler:";

    /**
     * 对不能单独处理的异常进行统一处理
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public TxnRespResult txnExceptionHandler(Exception e) {
        logger.warn(EXCEPTION_HANDLER,e);
        return new TxnRespResult<>().getFail(TxnRespCode.ERROR.getCode(), TxnRespCode.ERROR.getUserTips());
    }

    /**
     * 对运行时异常进行统一处理
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = TxnRuntimeException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public TxnRespResult txnRuntimeExceptionHandler(TxnRuntimeException e) {
        logger.warn(EXCEPTION_HANDLER,e);
        return new TxnRespResult<>().getFail(TxnRespCode.ERROR.getCode(), TxnRespCode.ERROR.getUserTips());
    }

    /**
     * 对服务异常处理
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = TxnException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public TxnRespResult txnExceptionHandler(TxnException e) {
        logger.warn(EXCEPTION_HANDLER,e);
        return new TxnRespResult<>().getFail(e.getErrCode(), e.getErrMsg());
    }

    /**
     * 对拒绝异常处理
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = TxnForbiddenException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public TxnRespResult txnForbiddenExceptionHandler(TxnForbiddenException e) {
        logger.warn(EXCEPTION_HANDLER,e);
        return new TxnRespResult<>().getFail(e.getErrCode(), e.getErrMsg());
    }

    /**
     * 对未授权异常处理
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = TxnUnauthorizedException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public TxnRespResult txnUnauthorizedExceptionHandler(TxnUnauthorizedException e) {
        logger.warn(EXCEPTION_HANDLER,e);
        return new TxnRespResult<>().getFail(e.getErrCode(), e.getErrMsg());
    }

    /**
     * 对未发现异常处理
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = TxnNotFoundException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public TxnRespResult txnNotFoundExceptionHandler(TxnNotFoundException e) {
        logger.warn(EXCEPTION_HANDLER,e);
        return new TxnRespResult<>().getFail(e.getErrCode(), e.getErrMsg());
    }

    /**
     * 对错误的请求处理 包括参数检查错误
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = {TxnArgumentException.class, MethodArgumentNotValidException.class})
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public TxnRespResult txnArgumentExceptionHandler(Exception e) {
        if (e instanceof TxnArgumentException) {
            TxnArgumentException ex = (TxnArgumentException) e;
            logger.warn("TxnArgumentException:",e);
            return new TxnRespResult<>().getFail(ex.getErrCode(), ex.getErrMsg());
        } else if (e instanceof MethodArgumentNotValidException) {
            logger.warn("MethodArgumentNotValidException:",e);
            return methodArgumentNotValidExceptionHandler((MethodArgumentNotValidException) e);
        } else {
            logger.warn(EXCEPTION_HANDLER,e);
            return new TxnRespResult<>().getFail(TxnRespCode.PARAM_ERROR.getCode(), TxnRespCode.PARAM_ERROR.getUserTips());
        }
    }

    private TxnRespResult methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException ex) {
        TxnRespResult result = new TxnRespResult();
        // 参数校验异常
        List<ObjectError> errors = ex.getBindingResult().getAllErrors();
        if (!errors.isEmpty()) {
            // 获取所有出错字段及错误信息，FieldName -> ErrorMessage (字段名称 -> 对应的错误信息)
            StringBuilder errorFieldMsg = new StringBuilder();
            for (ObjectError error : errors) {
                if (error instanceof FieldError) {
                    FieldError fieldError = (FieldError) error;
                    errorFieldMsg.append(fieldError.getDefaultMessage()).append(";");

                    logger.info("参数校验失败, field={}, errorMsg={}, fieldValue={}",
                            fieldError.getField(), fieldError.getDefaultMessage(), fieldError.getRejectedValue());
                }
            }
            // 将校验失败的字段的错误信息放到result的message中
            result.getFail(TxnRespCode.PARAM_ERROR.getCode(), TxnRespCode.PARAM_ERROR.getUserTips());
        } else {
            result.getFail(TxnRespCode.PARAM_ERROR.getCode(), TxnRespCode.PARAM_ERROR.getUserTips());
        }
        return result;
    }

    @ExceptionHandler(value = {TxnBeanMappingException.class})
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public TxnRespResult txnBeanMappingExceptionHandler(TxnBeanMappingException e) {
        logger.warn(EXCEPTION_HANDLER,e);
        return new TxnRespResult<>().getFail(e.getErrCode(), e.getErrMsg());
    }

    /**
     * 参数类型转换错误
     *
     * @param exception 错误
     * @return 错误信息
     */
    @ExceptionHandler(HttpMessageConversionException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public TxnRespResult parameterTypeException(HttpMessageConversionException exception) {

        logger.warn("HttpMessageConversionException:",exception);
        String soap = exception.getCause().getLocalizedMessage();

        String reportMsg="Unexpected character";
        if (soap.contains(reportMsg)){
            logger.warn("请求中报文中含有非法字符");
            return  new TxnRespResult().getFail(TxnRespCode.PARAM_ERROR.getCode(),TxnRespCode.PARAM_ERROR.getUserTips());
        }
        // 匹配的模式
        Matcher matcher = pattern.matcher(soap);
        String param = "";
        int i = 0;
        String listParam = "";
        String listIndex = "";
        while (matcher.find(i)) {
            String term = matcher.group(1);
            if (term.contains("List")) {
                listParam = term;
            }
            if (StringUtils.isNumber(term)) {
                listIndex = term;
            }
            param = term;
            i = matcher.end() + 1;
        }
        if (!"".equalsIgnoreCase(listParam)) {
            logger.warn("集合[" + listParam + "]的下标为[" + listIndex + "]的对象的属性[" + param + "]的参数不正确，导致类型转换错误");
            return new TxnRespResult().getFail(TxnRespCode.PARAM_ERROR.getCode(), TxnRespCode.PARAM_ERROR.getUserTips());
        }
        logger.warn("请求中的" + param + "参数不正确，导致类型转换错误");
        return new TxnRespResult().getFail(TxnRespCode.PARAM_ERROR.getCode(), TxnRespCode.PARAM_ERROR.getUserTips());

    }
}